### -*- coding: utf-8 -*- #############################################
# Разработано Паэглит Арвидом (http://arvid.dp.ua/)
# Все права защищены, 2007
#
# Developed by Paeglit Arvid (http://arvid.dp.ua/)
# All right reserved, 2007
#######################################################################
"""Chromosome class for the Zope 3 based diplom.expo package

$Id: chromosome.py 66 2007-12-28 23:05:19Z Arvi3D $
"""
__author__  = "Arvid"
__license__ = "GPL"
__version__ = "$Revision: 66 $"
__date__ = "$Date: 2007-12-29 01:05:19 +0200 (Sat, 29 Dec 2007) $"

from zope.schema.fieldproperty import FieldProperty
from zope.schema import getFieldsInOrder, getFieldNames
from zope.interface import implements,implementedBy
from zope.cachedescriptors.property import CachedProperty
from zope.app import zapi

from random import random, expovariate, randint
from math import sqrt, exp, log

from interfaces import IChromosomeFactory
from diplom.interfaces import IDistributingFactory

BITS = 10
weightFunc = lambda p : float(p)/(2**BITS - 1)

class ChromosomeFactory(object):
    """factory in genetic algorithm"""
    implements(IChromosomeFactory)

    coef = [2**i for i in range(BITS)]

    def __init__(self, data):
        self.data = data
        self.vectorZIP = zip(data.vector[1:], data.vector)
        self.firstFactory = zapi.getUtility(IDistributingFactory, name = data.firstDistr, context = self)
        self.secondFactory = zapi.getUtility(IDistributingFactory, name = data.secondDistr, context = self)
        self.n = BITS*(len(getFieldNames(self.firstFactory.params))+len(getFieldNames(self.secondFactory.params)) + 1)

        super(ChromosomeFactory, self).__init__()

    def evalFunc(self, weight, paramlist) : \
        return -sqrt(self.data.classCount)*max(map(lambda z : abs(self.data.distributing(z[1])
                                                    - self.data.teoreticalDistributing(z[0],
                                                                            weight,
                                                                            paramlist,
                                                                            )
                                                                   )
                                                , self.vectorZIP)
                                                )

    def generate(self):
        return map(lambda i : randint(0,1), range(self.n))

    def eval(self, chromosome):
        weight, paramlist = self.params(chromosome)
        return self.evalFunc(weight, paramlist)

    def params(self, chromosome):
        """get params"""
        chrom = lambda idx : sum(map(lambda i : chromosome[i + idx]*self.coef[i], range(BITS)))

        weight = weightFunc(chrom(0))
        paramlist = []

        index = 10
        for d, c in ((getFieldsInOrder(self.firstFactory.params), self.firstFactory.constraints)
                    , (getFieldsInOrder(self.secondFactory.params), self.secondFactory.constraints)):
            paramlist.append([])
            for n, p in d:
                #Здесь пока имеется ввиду нижняя граница равная нулю
                v = c[n](self.data)[1]
                paramlist[-1].append( (n, chrom(index)*v/(2**BITS-1) ) )
                index += BITS

        return (weight, paramlist)
